[小ネタ]Session ManagerでアクセスできるEC2を1発で作成するCloudFormationテンプレート作ってみた
こんにちはオンジーこと恩塚です!
パパッと検証でEC2を起動してセッションマネージャーでコマンドを試したいっていうときに今までマネジメントコンソールからポチポチやってたのですが、一発で構築したくなってCloudFormationテンプレートを作ってみました。
テンプレート(yamlファイル)
AWSTemplateFormatVersion: "2010-09-09" Parameters: EnvironmentName: Type: String Default: xxxxxxxx-env VPCCIDR: Type: String Default: 10.192.0.0/16 PrivateSubnetCIDR: Type: String Default: 10.192.0.0/24 Ec2ImageId: Type: AWS::SSM::Parameter::Value<String> Default: /aws/service/ami-amazon-linux-latest/amzn2-ami-hvm-x86_64-gp2 Ec2InstanceType: Type: String Default: t3.nano KeyPair: Type: String Default: xxxxx-key Resources: VPC: Type: AWS::EC2::VPC Properties: CidrBlock: !Ref VPCCIDR EnableDnsSupport: true EnableDnsHostnames: true Tags: - Key: Name Value: !Sub ${EnvironmentName}-VPC PrivateSubnet: Type: AWS::EC2::Subnet Properties: AvailabilityZone: !Select [0, !GetAZs ""] CidrBlock: !Ref PrivateSubnetCIDR VpcId: !Ref VPC Tags: - Key: Name Value: !Sub ${EnvironmentName}-PrivateSubnet PrivateRouteTable: Type: AWS::EC2::RouteTable Properties: VpcId: !Ref VPC Tags: - Key: Name Value: !Sub ${EnvironmentName}-PrivateRouteTable PrivateSubnetRouteTableAssociation: Type: AWS::EC2::SubnetRouteTableAssociation Properties: SubnetId: !Ref PrivateSubnet RouteTableId: !Ref PrivateRouteTable EndpointSecurityGroup: Type: AWS::EC2::SecurityGroup Properties: GroupDescription: EndpointSecurityGroup VpcId: !Ref VPC Tags: - Key: Name Value: !Sub ${EnvironmentName}-EndpointSecurityGroup SecurityGroupIngress: - IpProtocol: tcp FromPort: 443 ToPort: 443 CidrIp: !Ref VPCCIDR EndpointSSM: Type: AWS::EC2::VPCEndpoint Properties: PrivateDnsEnabled: true SecurityGroupIds: - !Ref EndpointSecurityGroup ServiceName: !Sub com.amazonaws.${AWS::Region}.ssm SubnetIds: - !Ref PrivateSubnet VpcEndpointType: Interface VpcId: !Ref VPC EndpointSSMMessages: Type: AWS::EC2::VPCEndpoint Properties: PrivateDnsEnabled: true SecurityGroupIds: - !Ref EndpointSecurityGroup ServiceName: !Sub com.amazonaws.${AWS::Region}.ssmmessages SubnetIds: - !Ref PrivateSubnet VpcEndpointType: Interface VpcId: !Ref VPC EndpointEC2Messages: Type: AWS::EC2::VPCEndpoint Properties: PrivateDnsEnabled: true SecurityGroupIds: - !Ref EndpointSecurityGroup ServiceName: !Sub com.amazonaws.${AWS::Region}.ec2messages SubnetIds: - !Ref PrivateSubnet VpcEndpointType: Interface VpcId: !Ref VPC EndpointS3: Type: AWS::EC2::VPCEndpoint Properties: RouteTableIds: - !Ref PrivateRouteTable ServiceName: !Sub com.amazonaws.${AWS::Region}.s3 VpcEndpointType: Gateway VpcId: !Ref VPC EC2IAMRole: Type: AWS::IAM::Role Properties: RoleName: !Sub ${EnvironmentName}-SSM-role AssumeRolePolicyDocument: Version: 2012-10-17 Statement: - Effect: Allow Principal: Service: - ec2.amazonaws.com Action: - sts:AssumeRole Path: / ManagedPolicyArns: - arn:aws:iam::aws:policy/AmazonSSMManagedInstanceCore EC2InstanceProfile: Type: AWS::IAM::InstanceProfile Properties: Path: / Roles: - Ref: EC2IAMRole InstanceProfileName: !Sub ${EnvironmentName}-EC2InstanceProfile EC2SecurityGroup: Type: AWS::EC2::SecurityGroup Properties: GroupDescription: EC2SecurityGroup VpcId: !Ref VPC Tags: - Key: Name Value: !Sub ${EnvironmentName}-EC2SecurityGroup EC2Instance: Type: AWS::EC2::Instance Properties: InstanceType: !Ref Ec2InstanceType SubnetId: !Ref PrivateSubnet ImageId: !Ref Ec2ImageId SecurityGroupIds: - !Ref EC2SecurityGroup IamInstanceProfile: !Ref EC2InstanceProfile BlockDeviceMappings: - DeviceName: /dev/xvda Ebs: VolumeSize: 100 VolumeType: gp2 EbsOptimized: true SourceDestCheck: true KeyName: !Ref KeyPair Tags: - Key: Name Value: !Sub ${EnvironmentName}-EC2Instance Outputs: VPC: Value: !Ref VPC Export: Name: !Sub ${EnvironmentName}-VPC VPCCIDR: Value: !Ref VPCCIDR Export: Name: !Sub ${EnvironmentName}-VPCCIDR PrivateSubnet: Value: !Ref PrivateSubnet Export: Name: !Sub ${EnvironmentName}-PrivateSubnet PrivateRouteTable: Value: !Ref PrivateRouteTable Export: Name: !Sub ${EnvironmentName}-PrivateRouteTable SecurityGroup: Value: !Ref EndpointSecurityGroup Export: Name: !Sub ${EnvironmentName}-EndpointSecurityGroup EndpointSSM: Value: !Ref EndpointSSM Export: Name: !Sub ${EnvironmentName}-EndpointSSM EndpointSSMMessages: Value: !Ref EndpointSSMMessages Export: Name: !Sub ${EnvironmentName}-EndpointSSMMessages EndpointEC2Messages: Value: !Ref EndpointEC2Messages Export: Name: !Sub ${EnvironmentName}-EndpointEC2Messages EndpointS3: Value: !Ref EndpointS3 Export: Name: !Sub ${EnvironmentName}-EndpointS3 EC2SecurityGroup: Value: !Ref EC2SecurityGroup Export: Name: !Sub ${EnvironmentName}-EC2SecurityGroup EC2Instance: Value: !Ref EC2Instance Export: Name: !Sub ${EnvironmentName}-EC2Instance
ざっくり解説
キーペアは作成済みのものを指定しています。
またスタックの作成方法については他記事でたくさん紹介されているので割愛します。
このテンプレートで作成しているのは以下の通りです。
- VPC
- サブネット
- ルートテーブル
- VPCエンドポイント
- IAMロール
- EC2インスタンス
大事なところだけ抜き出して紹介します!
EndpointSecurityGroup: Type: AWS::EC2::SecurityGroup Properties: GroupDescription: EndpointSecurityGroup VpcId: !Ref VPC Tags: - Key: Name Value: !Sub ${EnvironmentName}-EndpointSecurityGroup SecurityGroupIngress: - IpProtocol: tcp FromPort: 443 ToPort: 443 CidrIp: !Ref VPCCIDR
エンドポイントに設定するセキュリティグループはインバウンドルールでVPCからの443ポートへのHTTPS通信を許可する必要があります。
EndpointSSM: Type: AWS::EC2::VPCEndpoint Properties: PrivateDnsEnabled: true SecurityGroupIds: - !Ref EndpointSecurityGroup ServiceName: !Sub com.amazonaws.${AWS::Region}.ssm SubnetIds: - !Ref PrivateSubnet VpcEndpointType: Interface VpcId: !Ref VPC EndpointSSMMessages: Type: AWS::EC2::VPCEndpoint Properties: PrivateDnsEnabled: true SecurityGroupIds: - !Ref EndpointSecurityGroup ServiceName: !Sub com.amazonaws.${AWS::Region}.ssmmessages SubnetIds: - !Ref PrivateSubnet VpcEndpointType: Interface VpcId: !Ref VPC EndpointEC2Messages: Type: AWS::EC2::VPCEndpoint Properties: PrivateDnsEnabled: true SecurityGroupIds: - !Ref EndpointSecurityGroup ServiceName: !Sub com.amazonaws.${AWS::Region}.ec2messages SubnetIds: - !Ref PrivateSubnet VpcEndpointType: Interface VpcId: !Ref VPC EndpointS3: Type: AWS::EC2::VPCEndpoint Properties: RouteTableIds: - !Ref PrivateRouteTable ServiceName: !Sub com.amazonaws.${AWS::Region}.s3 VpcEndpointType: Gateway VpcId: !Ref VPC
プライベートサブネットにあるEC2インスタンスにセッションマネージャーで繋ぐには全部で4つのVPCエンドポイントが必要になるのでこの部分で作成しています。
- com.amazonaws.region.ssm
- com.amazonaws.region.ec2messages
- com.amazonaws.region.ssmmessages
- com.amazonaws.region.s3
EC2IAMRole: Type: AWS::IAM::Role Properties: RoleName: !Sub ${EnvironmentName}-SSM-role AssumeRolePolicyDocument: Version: 2012-10-17 Statement: - Effect: Allow Principal: Service: - ec2.amazonaws.com Action: - sts:AssumeRole Path: / ManagedPolicyArns: - arn:aws:iam::aws:policy/AmazonSSMManagedInstanceCore
セッションマネージャーでアクセスするためにはIAMポリシーのAmazonSSMManagedInstanceCoreがアタッチされているIAMロールがEC2インスタンスに設定されている必要があります。
作成したIAMロールをEC2のインスタンスプロファイルで指定します。
以上になります!